<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Index Uniqueness Checks</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REV="MADE"
HREF="mailto:pgsql-docs@postgresql.org"><LINK
REL="HOME"
TITLE="PostgreSQL 9.1.2 Documentation"
HREF="index.html"><LINK
REL="UP"
TITLE="Index Access Method Interface Definition"
HREF="indexam.html"><LINK
REL="PREVIOUS"
TITLE="Index Locking Considerations"
HREF="index-locking.html"><LINK
REL="NEXT"
TITLE="Index Cost Estimation Functions"
HREF="index-cost-estimation.html"><LINK
REL="STYLESHEET"
TYPE="text/css"
HREF="stylesheet.css"><META
HTTP-EQUIV="Content-Type"
CONTENT="text/html; charset=ISO-8859-1"><META
NAME="creation"
CONTENT="2011-12-01T22:07:59"></HEAD
><BODY
CLASS="SECT1"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="5"
ALIGN="center"
VALIGN="bottom"
><A
HREF="index.html"
>PostgreSQL 9.1.2 Documentation</A
></TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="top"
><A
TITLE="Index Locking Considerations"
HREF="index-locking.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="top"
><A
HREF="indexam.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="60%"
ALIGN="center"
VALIGN="bottom"
>Chapter 52. Index Access Method Interface Definition</TD
><TD
WIDTH="20%"
ALIGN="right"
VALIGN="top"
><A
TITLE="Index Cost Estimation Functions"
HREF="index-cost-estimation.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="INDEX-UNIQUE-CHECKS"
>52.5. Index Uniqueness Checks</A
></H1
><P
>   <SPAN
CLASS="PRODUCTNAME"
>PostgreSQL</SPAN
> enforces SQL uniqueness constraints
   using <I
CLASS="FIRSTTERM"
>unique indexes</I
>, which are indexes that disallow
   multiple entries with identical keys.  An access method that supports this
   feature sets <TT
CLASS="STRUCTNAME"
>pg_am</TT
>.<TT
CLASS="STRUCTFIELD"
>amcanunique</TT
> true.
   (At present, only b-tree supports it.)
  </P
><P
>   Because of MVCC, it is always necessary to allow duplicate entries to
   exist physically in an index: the entries might refer to successive
   versions of a single logical row.  The behavior we actually want to
   enforce is that no MVCC snapshot could include two rows with equal
   index keys.  This breaks down into the following cases that must be
   checked when inserting a new row into a unique index:

    <P
></P
></P><UL
><LI
><P
>       If a conflicting valid row has been deleted by the current transaction,
       it's okay.  (In particular, since an UPDATE always deletes the old row
       version before inserting the new version, this will allow an UPDATE on
       a row without changing the key.)
      </P
></LI
><LI
><P
>       If a conflicting row has been inserted by an as-yet-uncommitted
       transaction, the would-be inserter must wait to see if that transaction
       commits.  If it rolls back then there is no conflict.  If it commits
       without deleting the conflicting row again, there is a uniqueness
       violation.  (In practice we just wait for the other transaction to
       end and then redo the visibility check in toto.)
      </P
></LI
><LI
><P
>       Similarly, if a conflicting valid row has been deleted by an
       as-yet-uncommitted transaction, the would-be inserter must wait
       for that transaction to commit or abort, and then repeat the test.
      </P
></LI
></UL
><P>
  </P
><P
>   Furthermore, immediately before reporting a uniqueness violation
   according to the above rules, the access method must recheck the
   liveness of the row being inserted.  If it is committed dead then
   no violation should be reported.  (This case cannot occur during the
   ordinary scenario of inserting a row that's just been created by
   the current transaction.  It can happen during
   <TT
CLASS="COMMAND"
>CREATE UNIQUE INDEX CONCURRENTLY</TT
>, however.)
  </P
><P
>   We require the index access method to apply these tests itself, which
   means that it must reach into the heap to check the commit status of
   any row that is shown to have a duplicate key according to the index
   contents.  This is without a doubt ugly and non-modular, but it saves
   redundant work: if we did a separate probe then the index lookup for
   a conflicting row would be essentially repeated while finding the place to
   insert the new row's index entry.  What's more, there is no obvious way
   to avoid race conditions unless the conflict check is an integral part
   of insertion of the new index entry.
  </P
><P
>   If the unique constraint is deferrable, there is additional complexity:
   we need to be able to insert an index entry for a new row, but defer any
   uniqueness-violation error until end of statement or even later.  To
   avoid unnecessary repeat searches of the index, the index access method
   should do a preliminary uniqueness check during the initial insertion.
   If this shows that there is definitely no conflicting live tuple, we
   are done.  Otherwise, we schedule a recheck to occur when it is time to
   enforce the constraint.  If, at the time of the recheck, both the inserted
   tuple and some other tuple with the same key are live, then the error
   must be reported.  (Note that for this purpose, <SPAN
CLASS="QUOTE"
>"live"</SPAN
> actually
   means <SPAN
CLASS="QUOTE"
>"any tuple in the index entry's HOT chain is live"</SPAN
>.)
   To implement this, the <CODE
CLASS="FUNCTION"
>aminsert</CODE
> function is passed a
   <TT
CLASS="LITERAL"
>checkUnique</TT
> parameter having one of the following values:

    <P
></P
></P><UL
><LI
><P
>       <TT
CLASS="LITERAL"
>UNIQUE_CHECK_NO</TT
> indicates that no uniqueness checking
       should be done (this is not a unique index).
      </P
></LI
><LI
><P
>       <TT
CLASS="LITERAL"
>UNIQUE_CHECK_YES</TT
> indicates that this is a non-deferrable
       unique index, and the uniqueness check must be done immediately, as
       described above.
      </P
></LI
><LI
><P
>       <TT
CLASS="LITERAL"
>UNIQUE_CHECK_PARTIAL</TT
> indicates that the unique
       constraint is deferrable. <SPAN
CLASS="PRODUCTNAME"
>PostgreSQL</SPAN
>
       will use this mode to insert each row's index entry.  The access
       method must allow duplicate entries into the index, and report any
       potential duplicates by returning FALSE from <CODE
CLASS="FUNCTION"
>aminsert</CODE
>.
       For each row for which FALSE is returned, a deferred recheck will
       be scheduled.
      </P
><P
>       The access method must identify any rows which might violate the
       unique constraint, but it is not an error for it to report false
       positives. This allows the check to be done without waiting for other
       transactions to finish; conflicts reported here are not treated as
       errors and will be rechecked later, by which time they may no longer
       be conflicts.
      </P
></LI
><LI
><P
>       <TT
CLASS="LITERAL"
>UNIQUE_CHECK_EXISTING</TT
> indicates that this is a deferred
       recheck of a row that was reported as a potential uniqueness violation.
       Although this is implemented by calling <CODE
CLASS="FUNCTION"
>aminsert</CODE
>, the
       access method must <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>not</I
></SPAN
> insert a new index entry in this
       case.  The index entry is already present.  Rather, the access method
       must check to see if there is another live index entry.  If so, and
       if the target row is also still live, report error.
      </P
><P
>       It is recommended that in a <TT
CLASS="LITERAL"
>UNIQUE_CHECK_EXISTING</TT
> call,
       the access method further verify that the target row actually does
       have an existing entry in the index, and report error if not.  This
       is a good idea because the index tuple values passed to
       <CODE
CLASS="FUNCTION"
>aminsert</CODE
> will have been recomputed.  If the index
       definition involves functions that are not really immutable, we
       might be checking the wrong area of the index.  Checking that the
       target row is found in the recheck verifies that we are scanning
       for the same tuple values as were used in the original insertion.
      </P
></LI
></UL
><P>
  </P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="index-locking.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="index-cost-estimation.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Index Locking Considerations</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="indexam.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Index Cost Estimation Functions</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>